﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using CRMSimple.LogService.DataCacheExtensions.FileDataCache;
using BitAuto.EP.CRMLogSystem.Utils;
using BitAuto.EP.CRMLogSystem.Entity;
using CRMSimple.LogService.DataProtocol.Abstractions;
using System.Text.RegularExpressions;
using System.Threading;
using BitAuto.EP.Plat.Util;
using BitAuto.EP.FuncPMonitor.Aops;

namespace CRMSimple.LogServices
{
    public class TextFileDataCache : FileDataCacheRoot
    {
        /// <summary>
        /// 缓存程序路径和stream
        /// </summary>
        private IDictionary<string, Tuple<string[], Queue<string>>> appReadStreamCache = new Dictionary<string, Tuple<string[], Queue<string>>>();
        /// <summary>
        /// 缓存程序路径和stream
        /// </summary>
        private IDictionary<string, Tuple<string, FileStream>> appWriteStreamCache = new Dictionary<string, Tuple<string, FileStream>>();

        //private Tuple<string, FileStream> this[string key]
        //{
        //    get
        //    {
        //        //判断是否和配置文件中的一致（配置文件中是否有值）

        //        return appReadStreamCache.ContainsKey(key) ? appReadStreamCache[key] : null;
        //    }
        //    set
        //    {
        //        if (appReadStreamCache.ContainsKey(key))
        //        {
        //            //释放旧的stream
        //            var oldStream = appReadStreamCache[key];
        //            if (oldStream != null && oldStream.Item2 != null)
        //            {
        //                oldStream.Item2.Flush();
        //                oldStream.Item2.Dispose();
        //                oldStream = null;
        //            }
        //            appReadStreamCache[key] = value;
        //        }
        //        else
        //            appReadStreamCache.Add(key, value);
        //    }
        //}
        private Tuple<string, FileStream> this[string key, DateTime pushTime]
        {
            get
            {
                return appWriteStreamCache.ContainsKey(key) ? appWriteStreamCache[key] : null;
            }
            set
            {
                if (appWriteStreamCache.ContainsKey(key))
                {
                    //释放旧的stream
                    var oldStream = appWriteStreamCache[key];
                    if (oldStream != null && oldStream.Item2 != null)
                    {
                        oldStream.Item2.Flush();
                        oldStream.Item2.Dispose();
                        oldStream = null;
                    }
                    appWriteStreamCache[key] = value;
                    //写入配置文件新的路径
                }
                else
                    appWriteStreamCache.Add(key, value);
            }
        }

        #region 属性
        public string Extension { get { return AppConfig.GetAppSetting("TextFileDataCache:Extension"); } }

        private IDictionary<string, string> directoryPath = new Dictionary<string, string>();
        public string this[string key]
        {
            get
            {

                return directoryPath.ContainsKey(key) ? directoryPath[key] : this[key] = this.CheckDirectory(this.GetPhysicalFilePath(Path.Combine(AppConfig.GetAppSetting("TextFileDataCache:Directory"), key)));

            }
            set
            {
                if (directoryPath.ContainsKey(key))
                    directoryPath[key] = value;
                else
                    directoryPath.Add(key, value);

            }
        }
        public Tuple<string[], Queue<string>> this[string key, string flag = ""]
        {
            get
            {
                return appReadStreamCache.ContainsKey(key) ? appReadStreamCache[key] : this[key,flag] =Tuple.Create(new string[1],new Queue<string>());


            }
            set
            {
                if (appReadStreamCache.ContainsKey(key))
                    appReadStreamCache[key] = value;
                else
                    appReadStreamCache.Add(key, value);

            }
        }
        public ConfigurationManager config = Singleton<ConfigurationManager>.Instance;

        public static readonly string KeyDelimiter = "@|@";
        public readonly string Newline = "\r\n";//配置到配置文件去
        /// <summary>
        /// 文件命名规则
        /// </summary>
        /// <remarks>
        /// {0}:appkey
        /// {1}:count
        /// {2}:Extension
        /// </remarks>
        public string FileRule { get { return AppConfig.GetAppSetting("TextFileDataCache:FileRule"); } }//= "{0}_{1}.{2}"; 
        #endregion
        #region 实现
        /// <summary>
        /// 返回读取流
        /// </summary>
        protected override Stream CreateReadStream(string key)
        {
            var path = this.GetReadStreamPath(key);

            //var cache = this[key];
            //if (cache != null&&cache.Item2!=null)
            //    return cache.Item2;
            //else
            //{
            //this[key] = Tuple.Create<string, FileStream>(path, null);
            return new FileStream(path, FileMode.Open, FileAccess.Read);
            //}
        }
        /// <summary>
        /// 返回写入流
        /// </summary>
        protected override Stream CreateWirteStream(DataParam data)
        {
            string key = GetAppKey(data.Data);

            //var path = this.GetWriteStreamPath(data);
            Stream stream = null;
            var fileName = this.WriteTextFileName(key);
            var path = this.GetPath(key, fileName);
            //如果要生成新的文件
            if (!this.config[key, "WriteFileName"].Equals(fileName))
            {
                //设置旧文件属性为只读

                File.SetAttributes(this.GetPath(key, this.config[key, "WriteFileName"]), FileAttributes.ReadOnly);
                //file
                if (!File.Exists(path))
                    stream = File.Create(path);
                File.SetAttributes(path, FileAttributes.Normal);
                return stream;
            }
            else
                stream=new FileStream(path, FileMode.Append, FileAccess.Write);
            //var cache = this[key, data.PushTime];
            //if (cache != null&&cache.Item1==path && cache.Item2 != null)
            //    return cache.Item2;
            //else
            //{
            //config[key, "newCount"] = "0";
            //this[key, data.PushTime] = Tuple.Create<string, FileStream>(path, null);//this[key, data.PushTime].Item2
            return stream;
            //}
        }


        protected override string GetMsg(DataParam data)
        {
            var key = GetAppKey(data.Data);
            //附加行号，读取配置文件
            var newCount = EConvert.ToInt(config[key, "CurrentCount"], 0) + 1;
            //if (newCount > EConvert.ToInt(config[key, "ConsumeCount"], 0))
            //    newCount = 0;
            //DataLogHelper.M("写入了" + JsonHelper.Serialize(data) + "\r\nCurrentCount:" + newCount.ToString());
            config[key, "CurrentCount"] = newCount.ToString();
            return string.Format("{0}{1}{2}{3}", newCount.ToString(), KeyDelimiter, JsonHelper.Serialize(data), Newline);
        }
        /// <summary>
        /// 获取数据
        /// </summary>
        public T GetProducterData<T>(string key, out long postion) where T : class
        {
            var content = this.GetLine(key, out postion);

            if (string.IsNullOrEmpty(content)) return default(T);

            var index = content.IndexOf(KeyDelimiter);
            return this.GetModule<T>(index > -1 ? content.Split(new string[] { KeyDelimiter }, StringSplitOptions.None)[1] : content);
        }
        #endregion

        public string GetReadStreamPath(string key)
        {
            //当前要读的文件
            return this[key, "Queue"].Item1[0] = appReadStreamCache[key].Item2.Dequeue();
        }
        /// <summary>
        /// 将可处理文件加入队列
        /// </summary>
        private void AddQueue(string key)
        {
            var files = System.IO.Directory.GetFiles(this[key], "*.txt", SearchOption.TopDirectoryOnly);
            if (files != null && files.Any())
            {
                //var orderbyFiles= files.OrderBy(e => GetCurCountInFileName(Path.GetFileName(e)));
                int curCount = GetCurCountInFileName(config[key, "ReadFileName"])
                    , totalCount = EConvert.ToInt(this.config[key, "CreateFileCountTotal"], 10000);
                List<string> lessFiles = new List<string>(curCount)
                    , moreFiles = new List<string>(totalCount - curCount);
                foreach (var file in files)
                {
                    //如果是不包含在队列里且是只读的
                    if (!this[key, "Queue"].Item2.Contains(file) && (File.GetAttributes(file) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
                    {
                        if (GetCurCountInFileName(Path.GetFileName(file)) < curCount)
                            lessFiles.Add(file);
                        else
                            moreFiles.Add(file);
                    }
                }
                if (lessFiles.Any()) lessFiles.OrderBy(e => GetCurCountInFileName(Path.GetFileName(e)));
                if (moreFiles.Any()) moreFiles.OrderBy(e => GetCurCountInFileName(Path.GetFileName(e)));
                //添加入队列
                foreach (var item in moreFiles)
                {
                    appReadStreamCache[key].Item2.Enqueue(item);
                }
                foreach (var item in lessFiles)
                {
                    appReadStreamCache[key].Item2.Enqueue(item);
                }
            }
        }
        /// <summary>
        /// 是否存在可处理文件
        /// </summary>
        public bool ReadFileNameIsExists(string key)
        {
            return !string.IsNullOrEmpty(config[key, "ReadFileName"]) && config[key, "ReadFileName"] != config[key, "WriteFileName"];
        }
        private string GetAppKey(string message)
        {
            var dataInfo = this.GetModule<ProduceDataForMQ>(message);
            return dataInfo != null ? dataInfo.LogTableId.ToString() : string.Empty;
        }
         [FuncPMonitor()]
        public override void Get(Action<DataParam> action)
        {
            IDictionary<string, Tuple<string, IList<DataParam>>> list = new Dictionary<string, Tuple<string, IList<DataParam>>>(config.SQLDBConfiguration.Count);
            //this.GetFile(
            IList<DataParam> param;
            foreach (var item in config.SQLDBConfiguration)
            {
                //是否可读
                if (CanRead(item.LogTableId))
                {
                    param = GetDataParam(item.LogTableId, this.GetFile(item.LogTableId));
                    //DataLogHelper.M("读取" + JsonHelper.Serialize(param));
                    list.Add(item.LogTableId, Tuple.Create(this[item.LogTableId, "Queue"].Item1[0], param));
                    //将当前文件属性设置为可删除
                    File.SetAttributes(this[item.LogTableId, "Queue"].Item1[0],FileAttributes.Archive);
                }
            }
            if (action != null)
                action(new DataParam(JsonHelper.Serialize(list), DateTime.Now));
        }
        private IList<DataParam> GetDataParam(string key, string data)
        {
            if (string.IsNullOrEmpty(data)) return null;

            var lines = data.Split(new string[] { this.Newline }, StringSplitOptions.RemoveEmptyEntries);

            if (lines == null && !lines.Any()) return null;

            IList<DataParam> list = new List<DataParam>();
            //DataLogHelper.M("lines行数" + lines.Length);
            foreach (var item in lines)
            {
                list.Add(JsonHelper.Deserialize<DataParam>(item.Split(new string[] { KeyDelimiter }, StringSplitOptions.None)[1]));
                config[key, "ConsumeCount"] = (EConvert.ToInt(config[key, "ConsumeCount"]) + 1).ToString();
            }
            return list;
        }
    
        /// <summary>
        /// 获取文件名
        /// </summary>
        private string WriteTextFileName(string key)
        {
           
            int ConsumeCountTotal = EConvert.ToInt(this.config[key, "ConsumeCountTotal"])//处理行数
               , CurrentCount = EConvert.ToInt(this.config[key, "CurrentCount"])//当前行数
               , CreateFileCount = EConvert.ToInt(this.config[key, "CreateFileCount"]);//创建文件个数
            //如果当前行数大于写入最多行数或者当前写文件已经被设置为只读则创建新文件
            if (CurrentCount > ConsumeCountTotal - 1 || (File.GetAttributes(this.GetPath(key, this.config[key, "WriteFileName"])) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
            {
                ++CreateFileCount;
                if (CreateFileCount > EConvert.ToInt(this.config[key, "CreateFileCountTotal"], 10000))
                    CreateFileCount = 0;
                this.config[key, "CreateFileCount"] = CreateFileCount.ToString();

                config[key, "CurrentCount"] = "0";

                
            }
            return string.Format(FileRule, key, CreateFileCount.ToString(), this.Extension);
        }

        private int GetCurCountInFileName(string fileName)
        {
            if (string.IsNullOrEmpty(fileName) || !Regex.IsMatch(fileName, Regex.Replace(FileRule, "{.+}", ".+"))) return -1;

            return EConvert.ToInt(fileName.Split('_')[1].Split('.')[0]);
        }
        private bool CanRead(string key)
        {
            //// int curCount = GetCurCountInFileName(config[key, "ReadFileName"]);

            ////1.WriteFileName 为空表示是首次运行，返回不可读
            ////2.文件可读
            //if (string.IsNullOrEmpty(config[key, "WriteFileName"]) || this[key] != null && !File.Exists(this[key].Item1))//|| curCount == EConvert.ToInt(this.config[key, "CreateFileCount"])
            //{
            //    this.config[key, "EqualsTimeSpan"] = "";
            //    return false;
            //}
            ////下一个可读文件是否仍然是当前可读文件
            //if (!string.IsNullOrEmpty(config[key, "ReadFileName"]) && config[key, "ReadFileName"].Equals(GetNextReadTextFileName(key)))
            //{
            //    var EqualsCount = this.config[key, "EqualsTimeSpan"];
            //    if (string.IsNullOrEmpty(EqualsCount))
            //    {
            //        this.config[key, "EqualsTimeSpan"] = DateTime.Now.ToString();
            //    }
            //    else if ((DateTime.Now - EConvert.ToDateTime(EqualsCount)).Minutes > 0.1)
            //    {
            //        this.config[key, "EqualsTimeSpan"] = "";
            //        return true;
            //    }
            //    return false;
            //}


            //return true;
            if (appReadStreamCache[key].Item2.Count == 0)
            {
                AddQueue(key);
                //如果队列仍然无数据
                if (appReadStreamCache[key].Item2.Count == 0)
                {
                    Thread.Sleep(500);
                    AddQueue(key);
                    if (appReadStreamCache[key].Item2.Count == 0)
                    {
                        //将当前可读文件变为只读
                        File.SetAttributes(this.GetPath(key, this.config[key, "WriteFileName"]), FileAttributes.ReadOnly);
                        AddQueue(key);
                    }
                }
            }

            if (appReadStreamCache[key].Item2.Count == 0)
                return false;
            else
                return true;
        }

    }
}
